﻿using EcoTourEduca.BingYourMaps.Models;
using EcoTourEduca.BingYourMaps.Services;
using EcoTourEduca.BingYourMaps.ViewModels;
using Orchard;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Media.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EcoTourEduca.BingYourMaps.Drivers
{
    public class BingMapsLocationDriver : ContentPartDriver<BingMapsLocationPart>
    {
        private readonly IBingYourMapsService _bingYourMapsService;
        private readonly IMediaService _mediaService;
        private readonly IOrchardServices _orchardServices;
        private const string TemplateName = "Parts/BingMapsLocation";

        public BingMapsLocationDriver(IBingYourMapsService bingYourMapsService,
                            IMediaService mediaService,
                            IOrchardServices orchardServices)
        {
            _bingYourMapsService = bingYourMapsService;
            _mediaService = mediaService;
            _orchardServices = orchardServices;
        }

        protected override string Prefix
        {
            get
            {
                return "BingMapsLocation";
            }
        }

        // Display method for BingMapsLocation
        protected override DriverResult Display(BingMapsLocationPart locationPart, 
                                    string displayType, dynamic shapeHelper)
        {
            if (locationPart.HideMap)
            {
                return null;
            }

            return ContentShape
            (   "Parts_BingMapsLocation", 
                () => shapeHelper.Parts_BingMapsLocation(
                    FriendlyName: locationPart.FriendlyName
                    ,Latitude: locationPart.Latitude
                    ,Longitude: locationPart.Longitude
                    ,MapHeight: locationPart.MapHeight
                    ,MapWidth: locationPart.MapWidth
                    ,MapType: locationPart.MapType
                    ,MapZoom: locationPart.MapZoom
                    ,PinIcon: locationPart.PinIcon
                    ,PinIconsFoler: GetIconsFolder())
            );
            // TODO: I need something else representing the place added here. Otherwise by the time I represent these
            // into a BingMapsAreaPar the pins popups won't show anything but the title
        }

        // GET
        protected override DriverResult Editor(BingMapsLocationPart locationPart, dynamic shapeHelper)
        {
            EditBingMapsLocationViewModel vm = BuildBingMapsLocationViewModel(locationPart);
            return ContentShape
            (
                "Parts_BingMapsLocation_Edit",
                () => shapeHelper.EditorTemplate(
                    TemplateName: TemplateName,
                    Model: vm, //BuildBingMapsLocationViewModel(locationPart),
                    Prefix: Prefix)
            );
        }

        // POST
        protected override DriverResult Editor(BingMapsLocationPart locationPart, 
                                    IUpdateModel updater, dynamic shapeHelper)
        {
            // Update main bits of location
            var ok = updater.TryUpdateModel(locationPart, Prefix, null, null);

            // Update linked maplist bit of location
            var viewModel = new EditBingMapsLocationViewModel();
            ok = updater.TryUpdateModel(viewModel, Prefix, null, null);

            // Gets value from String version (means it also works in French)
            locationPart.Latitude = viewModel.Latitude;
            locationPart.Longitude = viewModel.Longitude;
            //locationPart.HideMap = viewModel.HideMap;

            if (locationPart.ContentItem.Id != 0)
            {
                // This condition is necessary so this doesn't execute unless the post to the DB is done
                _bingYourMapsService.UpdateBingMapAreas(locationPart, viewModel);
            }

            return Editor(locationPart, shapeHelper);
        }

        /// <summary>
        /// Builds the BingMapsLocationViewModel to render the view.
        /// </summary>
        /// <param name="locationPart"></param>
        /// <returns></returns>
        private EditBingMapsLocationViewModel BuildBingMapsLocationViewModel(BingMapsLocationPart locationPart)
        {
            // Setting creation defaults - MapType is null on creation
            var mapType = locationPart.MapType ?? _bingYourMapsService.DefaultMapType;
            var hideMap = (locationPart.MapType != null) ? locationPart.HideMap : false;
            var areasForLocation = 
                _bingYourMapsService.ExistsBingMapsLocationPart(locationPart.Id) ?
                _bingYourMapsService.GetBingMapsAreasForLocationPart(locationPart.Id) :
                _bingYourMapsService.GetAllBingMapsAreas();

            var editViewModel = new EditBingMapsLocationViewModel
            {
                LatitudeStr = locationPart.Latitude.ToInvariantCultureString()
                ,LongitudeStr = locationPart.Longitude.ToInvariantCultureString()
                ,MapWidth = locationPart.MapWidth
                ,MapHeight = (locationPart.MapHeight <= 0) ? 
                    EditBingMapsLocationViewModel.DefaultMapHeight 
                    : locationPart.MapHeight
                ,MapZoom = locationPart.MapZoom
                ,MapType = mapType
                ,BingMapAreas = areasForLocation != null ? areasForLocation.ToList() : new List<BingMapsAreaViewModel>()
                ,MapTypeList = _bingYourMapsService.CreateMapTypeList(mapType)
                ,PossiblePinIcons = GetPossiblePinIcons()
                ,PinIcon = locationPart.PinIcon
                ,PinIconsFolder = GetIconsFolder()
                ,HideMap = hideMap
                ,FriendlyName = locationPart.FriendlyName
            };

            return editViewModel;
        }

        /// <summary>
        /// Returns list of possible pin icons for the map.
        /// </summary>
        /// <returns></returns>
        private IEnumerable<String> GetPossiblePinIcons()
        {
            // Get possible icons
            List<String> possiblePinIcons;
            var rootMediaFolders = _mediaService
                .GetMediaFolders(".")
                .Where(f => f.Name.Equals(BingYourMapsService.MAPICONS_MEDIA_FOLDER, StringComparison.OrdinalIgnoreCase));
            if (rootMediaFolders.Any())
            {
                possiblePinIcons = new List<string>(
                    _mediaService.GetMediaFiles(BingYourMapsService.MAPICONS_MEDIA_FOLDER)
                    .Select(f => f.Name));
            }
            else
            {
                possiblePinIcons = new List<String>();
            }

            return possiblePinIcons;
        }

        /// <summary>
        /// Returns the name of the folder hosting the available pin icons.
        /// </summary>
        /// <returns></returns>
        private String GetIconsFolder()
        {
            return _mediaService.GetPublicUrl(BingYourMapsService.MAPICONS_MEDIA_FOLDER + "/");
        }
    }
}